package model;



import java.lang.reflect.Modifier;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import java.util.LinkedHashMap;
import java.util.Map;

import util.GAConfig;
public class Filter {
	  private static final boolean notSilent= false;
	 private static Map<Class<?>, Boolean> cached_isVisible =new LinkedHashMap<Class<?>, Boolean>();

	 public static boolean isObjectType(Class<?> clz) {
		 if(clz.getCanonicalName()!=null)
			return clz ==  java.lang.Object.class ||clz.getCanonicalName().equals("java.lang.Comparable");
		 return false;
		}
	 public static boolean canUse(Class<?> c) {
	        if(Modifier.isAbstract(c.getModifiers()) || !Filter.isVisible(c))
	            return false;		 
		 return true;
		  }
	  public static boolean canUse(Constructor<?> c) {
		    if (Modifier.isAbstract(c.getDeclaringClass().getModifiers())){
			      System.out.println("Will not use: " + c.toString());
			      return false;
		    }
		    return Filter.isVisible (c.getModifiers());
		  }

		  public static boolean canUse(Method m) {

		    // If it's a main entry method, don't use it (we're doing unit
		    // testing, not running programs).
		    Class<?>[] paramTypes = m.getParameterTypes();
		    if (m.getName().equals("main")
		        && paramTypes.length == 1
		        && paramTypes[0].isArray()
		        && paramTypes[0].getComponentType().equals(String.class)) {
		      if (notSilent){
		        System.out.println("Will not use: " + m.toString());
		        System.out.println("  reason: main method not applicable to unit testing.");
		      }
		      return false;
		    }
		    if (m.getName().contains("$"))
		    		return false;

		    if (m.isBridge()){
		      if (notSilent){
		        System.out.println("Will not use: " + m.toString());
		        System.out.println("  reason: it's a bridge method");
		      }
		      return false;
		    }

		    if (m.isSynthetic()){
		      if (notSilent){
		        System.out.println("Will not use: " + m.toString());
		        System.out.println("  reason: it's a synthetic method");
		      }
		      return false;
		    }

		    if (!Filter.isVisible (m.getModifiers()))
		      return false;

		    if (m.getDeclaringClass().equals(java.lang.Object.class))
		      return false;//handled here to avoid printing reasons

		    if (m.getDeclaringClass().equals(java.lang.Thread.class))
		      return false;//handled here to avoid printing reasons

		    if (m.getAnnotation(CheckRep.class) != null) {
				      if (notSilent){
				        System.out.println("Will not use: " + m.toString());
				        System.out.println("  reason: there is Annoptation method");
				      }

		      return false;
		    }
		    

		    return true;
		  }
		  public static boolean isVisible(Class<?> c){

			     Boolean cached = cached_isVisible.get(c);
			     if (cached == null) {
			       if (c.isAnonymousClass()) {
			         cached = false;
			       } else {
			         int mods = c.getModifiers();
			         boolean classVisible = isVisible (mods);
			         if (c.isMemberClass())
			           cached = classVisible && isVisible(c.getDeclaringClass());
			         else
			           cached = classVisible;
			       }
			       cached_isVisible.put(c, cached);
			     }
			     assert cached != null;
			     return cached;
			   }
	  public static boolean isVisible (int modifiers) {
		    // System.out.printf ("isVisible public_only=%b, modifiers = %s%n",
		    if (GAConfig.public_only) {
		      return Modifier.isPublic (modifiers);
		    } else {
		      return !Modifier.isPrivate (modifiers);
		    }
		  }
	   public static boolean areAllVisible(Class<?>[] classes) {
		      for(Class<?> clz : classes) {
		        if(!Filter.isVisible(clz)) {
		          return false;
		        }
		      }
		      return true;
		    }

	   public static boolean isAbstract(Class<?> c) {
		     return Modifier.isAbstract (c.getModifiers());
		   }
	   public static boolean isPrimitiveOrStringType(Class<?> type) {
		    return primitiveAndStringType.containsKey(type);
		  }
	   public static final Map<Class<?>, Class<?>> primitiveAndStringType
	   = new LinkedHashMap<Class<?>, Class<?>>(9);

	   static {
		   primitiveAndStringType.put(boolean.class, Boolean.class);
		   primitiveAndStringType.put(byte.class, Byte.class);
		   primitiveAndStringType.put(char.class, Character.class);
		   primitiveAndStringType.put(double.class, Double.class);
		   primitiveAndStringType.put(float.class, Float.class);
		   primitiveAndStringType.put(int.class, Integer.class);
		   primitiveAndStringType.put(long.class, Long.class);
		   primitiveAndStringType.put(short.class, Short.class);
		   primitiveAndStringType.put(String.class, String.class);
		   
		    primitiveAndStringType.put(Integer.class,   Integer.class);
		    primitiveAndStringType.put(Boolean.class,   Boolean.class);
		    primitiveAndStringType.put(Float.class,     Float.class);
		    primitiveAndStringType.put(Character.class, Character.class);
		    primitiveAndStringType.put(Double.class,    Double.class);
		    primitiveAndStringType.put(Long.class,      Long.class);
		    primitiveAndStringType.put(Short.class,     Short.class);
		    primitiveAndStringType.put(Byte.class,      Byte.class); 
		   
	   }

	   public static Class<?> getPrimitiveTypeOrString(String typeName){
		    return typeNameToPrimitiveOrString.get(typeName);
		  }
	   protected static final Map<String, Class<?>> typeNameToPrimitiveOrString= new LinkedHashMap<String, Class<?>>();
	static {
			typeNameToPrimitiveOrString.put("void", void.class);
			typeNameToPrimitiveOrString.put("int", int.class);
			typeNameToPrimitiveOrString.put("java.lang.Integer", int.class);
			typeNameToPrimitiveOrString.put("boolean", boolean.class);
			typeNameToPrimitiveOrString.put("float", float.class);
			typeNameToPrimitiveOrString.put("java.lang.Float", float.class);
			typeNameToPrimitiveOrString.put("char", char.class);
			typeNameToPrimitiveOrString.put("java.lang.Character", char.class);
			typeNameToPrimitiveOrString.put("double", double.class);
			typeNameToPrimitiveOrString.put("java.lang.Double", double.class);
			typeNameToPrimitiveOrString.put("long", long.class);
			typeNameToPrimitiveOrString.put("java.lang.Long", long.class);
			typeNameToPrimitiveOrString.put("short", short.class);
			typeNameToPrimitiveOrString.put("java.lang.Short", short.class);
			typeNameToPrimitiveOrString.put("byte", byte.class);
			typeNameToPrimitiveOrString.put("java.lang.Byte", byte.class);
			typeNameToPrimitiveOrString.put(String.class.getName(), String.class);
			typeNameToPrimitiveOrString.put("Character", char.class);
			typeNameToPrimitiveOrString.put("String", String.class);
			typeNameToPrimitiveOrString.put("Boolean", boolean.class);
	}
		 public static boolean isNumeric(Object str)
		 {
			  try  
			  {  
			///	parseInt(str)
			    int d = Integer.valueOf((String) str);
			  }  
			  catch(NumberFormatException nfe)  
			  {  
			    return false;  
			  }  
			  return true;  

		   //  return str.matches("[+-]?\\d*(\\.\\d+)?");
		 }



}
